package org.n.shop.service.impl;

import lombok.AllArgsConstructor;
import org.n.shop.domain.Do.SelectOrderDo;
import org.n.shop.domain.dto.InsertOrderDto;
import org.n.shop.domain.entity.Order;
import org.n.shop.domain.entity.OrderDetail;
import org.n.shop.mapper.CommodityMapper;
import org.n.shop.mapper.OrderDetailMapper;
import org.n.shop.mapper.OrderMapper;
import org.n.shop.mapper.ShoppingCartMapper;
import org.n.shop.result.RestResult;
import org.n.shop.result.RestResultBuilder;
import org.n.shop.service.OrderService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.sql.Time;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.n.shop.config.RedisConfig.PREFIX_ORDER;
import static org.n.shop.config.RedisConfig.PREFIX_USER;

@Service
@AllArgsConstructor
public class OrderServiceImpl implements OrderService {
    private OrderMapper orderMapper;
    private OrderDetailMapper orderDetailMapper;
    private ShoppingCartMapper shoppingCartMapper;
    private CommodityMapper commodityMapper;
    private RedisTemplate redisTemplate;
    private TransactionDefinition transactionDefinition;
    private PlatformTransactionManager platformTransactionManager;

    @Override
    public RestResult add(String authorization, List<InsertOrderDto> insertOrderDto) {
        int userId = (int) redisTemplate.opsForValue().get(PREFIX_USER + authorization);

        Order order = Order.builder()
                .addressId(insertOrderDto.get(0).getAddressId())
                .userId(userId)
                .build();

        if (orderMapper.insertOrder(order) != 1) {
            return new RestResultBuilder().fail();
        }

        int orderId = orderMapper.getLastOrderId();

        List<OrderDetail> orderDetails = new ArrayList<>();
        int[] shoppingCartIds = new int[insertOrderDto.size()];
        String shoppingCartId = "";
        int i = 0;

        for (InsertOrderDto insertOrderDto1 : insertOrderDto) {
            OrderDetail orderDetail = OrderDetail.builder()
                    .commodityId(insertOrderDto1.getCommodityId())
                    .orderId(orderId)
                    .logistics(insertOrderDto1.getLogistics() == 0 ? "快递运输" : "上门自提")
                    .number(insertOrderDto1.getNumber())
                    .price(insertOrderDto1.getPrice() * insertOrderDto1.getNumber())
                    .build();
            orderDetails.add(orderDetail);
            shoppingCartIds[i++] = insertOrderDto1.getShoppingCartId();
            shoppingCartId += insertOrderDto1.getShoppingCartId() + ",";
        }

        if (orderDetailMapper.insertBatch(orderDetails) != orderDetails.size()) {
            return new RestResultBuilder().fail();
        }

        if (shoppingCartMapper.del(shoppingCartIds) != orderDetails.size()) {
            return new RestResultBuilder().fail();
        }

        redisTemplate.opsForValue().set(PREFIX_ORDER + orderId + "|" + shoppingCartId.substring(0, shoppingCartId.length() - 1),
                1, 30, TimeUnit.MINUTES);
        order.setUserId(0);
        order.setAddressId(0);
        order.setOrderId(orderId);
        return new RestResultBuilder().success(order);
    }

    @Override
    public RestResult pay(int orderId) {
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        if (commodityMapper.reduceStocks() != orderDetailMapper.totalAllOrderDetailByOrderId(orderId)) {
            platformTransactionManager.rollback(transactionStatus);
            return new RestResultBuilder().fail("支付失败 库存不够");
        }
        platformTransactionManager.commit(transactionStatus);

        if (orderDetailMapper.updateLogisticsType(orderId, 1) == 0) {
            return new RestResultBuilder().fail("支付失败");
        }

        redisTemplate.delete(PREFIX_ORDER + orderId);

        return new RestResultBuilder().success();
    }

    @Override
    public RestResult selectOrderById(int id) {
        SelectOrderDo selectOrderDo = orderMapper.selectOrder(id);
        selectOrderDo.setEndTime(selectOrderDo.getEndTime().plusMinutes(30));
        return new RestResultBuilder().success(
                selectOrderDo
        );
    }
}
